package com.gitee.baqkft.code.core.beans;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gitee.baqkft.code.core.util.FreemarkerUtils;
import com.gitee.baqkft.code.core.util.StringUtils;
import com.gitee.baqkft.code.db.DBColumn;
import com.gitee.baqkft.code.db.DBTable;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * java bean文件生成器
 * @author chenmingcai
 * @date 2018年5月21日 下午2:52:45
 *
 */

public class BeanFileHandler
{
	private Logger logger = LoggerFactory.getLogger(getClass());

	private static final String BEAN_TEMPLATE = "bean_templ.ftl";

	/**
	 * 实例
	 */
	private static BeanFileHandler handler;

	/**
	 * 类型映射表
	 */
	private static Map<String, String> typeTable = new HashMap<String, String>()
	{
		private static final long serialVersionUID = 1L;

		{
			put("VARCHAR", "String");
			put("CHAR", "String");
			put("INT", "Integer");
			put("BIGINT", "Long");
			put("DECIMAL", "Double");
			put("DOUBLE", "Double");
			put("FLOAT", "Double");
			put("TIMESTAMP", "Date");
			put("DATETIME", "Date");
			put("TINYINT", "int");
			put("BLOB", "byte[]");
			put("LONGBLOB", "byte[]");
			put("TEXT", "String");
			put("BIT", "Boolean");
		}
	};

	/**
	 * freeMarker配置
	 */
	private Configuration freemarkerConfig;

	private BeanFileHandler()
	{
		freemarkerConfig = FreemarkerUtils.defaultConfiguration();
		freemarkerConfig.setClassLoaderForTemplateLoading(Thread.currentThread().getContextClassLoader(), "template");
	}

	/**
	 * 获取实例
	 * @return
	 */
	public static BeanFileHandler getHandler()
	{
		if(handler == null)
		{
			handler = new BeanFileHandler();
		}
		return handler;
	}

	/**
	 * 生成java bean程序文件
	 * @param bean	bean模型
	 * @param dir
	 */
	public void makeBeanFile(BeanModel bean, String dir)
	{
		File dirFile = new File(dir);
		if(!dirFile.exists())
		{
			logger.error("{}不是目录", dir);
			throw new IllegalArgumentException("非法目录参数");
		}

		String beanFile = dir + File.separatorChar + bean.getClazzName() + ".java";
		File file = new File(beanFile);
		try
		{
			FileOutputStream fos = new FileOutputStream(file);
			Template tmpl = FreemarkerUtils.loadTemplate(freemarkerConfig, BEAN_TEMPLATE);
			Map<Object, Object> model = new HashMap<>();
			model.put("bean", bean);
			model.put("handler", this);
			FreemarkerUtils.process(model, tmpl, fos);
		}
		catch(IOException ex)
		{
			logger.error("模板处理失败", ex);
		}
	}

	/**
	 * 生成java bean程序文件
	 * @param table	数据表
	 * @param dir
	 */
	public void makeBeanFile(DBTable table, String dir)
	{
		if(table == null)
		{
			return;
		}

		//数据转换
		BeanModel bean = toBeanModel(table);
		makeBeanFile(bean, dir);
	}

	/**
	 * 生成javaBean文件内容
	 * @param table
	 * @return
	 */
	public String makeBeanContent(DBTable table)
	{
		if(table == null)
			return "";

		final BeanModel bean = toBeanModel(table);
		Template tmpl = FreemarkerUtils.loadTemplate(freemarkerConfig, BEAN_TEMPLATE);
		Map<Object, Object> model = new HashMap<>();
		model.put("bean", bean);
		model.put("handler", this);
		return FreemarkerUtils.process(model, tmpl);
	}

	/**
	 * 批量生成java bean程序文件
	 * @param tables	数据表
	 * @param dir
	 */
	public void makeBeanFiles(List<DBTable> tables, String dir)
	{
		for(DBTable table : tables)
		{
			makeBeanFile(table, dir);
		}
	}

	/**
	 * 转换成Pascal命名
	 * @param text
	 * @return
	 */
	public String toPascal(String text)
	{
		return StringUtils.toPascalString(text);
	}

	/**
	 * 将数据表转换成java bean模型
	 * @param table
	 * @return
	 */
	public BeanModel toBeanModel(DBTable table)
	{
		BeanModel model = new BeanModel();
		model.setClazzName(StringUtils.toPascalString(table.getName()));
		model.setDescription(table.getComment());

		Iterator<DBColumn> iter = table.getColumns().iterator();
		DBColumn col;
		while(iter.hasNext())
		{
			col = iter.next();

			String type = typeTable.get(col.getType());
			if(type == null)
			{
				logger.warn("数据类型转换关系不明，暂不支持: {}", col.getType());
				continue;
			}

			String attr = StringUtils.toCamelString(col.getName());
			model.getAttrs().add(attr);

			model.getAttrTypes().put(attr, type);
			model.getAttrComments().put(attr, col.getComment());
		}

		return model;
	}
}
